#pragma once
namespace wang
{
	enum Color
	{
		RED,
		BLACK
	};
	template<class T>
	struct Node
	{
		T _data;
		Node* _left;
		Node* _right;
		Node* _parent;
		Color _col;

		Node(const T& data)
			:_data(data)
			, _col(RED)
		{ _left = _right = _parent = nullptr; }
	};

	template<class T>
	class rbtree
	{
		typedef Node<T> Node;
	public:
		bool insert(const T& data)
		{
			if (_root == nullptr)
			{
				_root = new Node(data);
				_root->_col = BLACK;
				return true;
			}
			Node* pcur = _root;
			Node* parent = nullptr;
			while (pcur)
			{
				parent = pcur;
				if (data < pcur->_data)
					pcur = pcur->_left;
				else if (data > pcur->_data)
					pcur = pcur->_right;
				else
					return false;
			}
			pcur = new Node(data);
			if (data < parent->_data)
				parent->_left = pcur;
			else
				parent->_right = pcur;
			pcur->_parent = parent;
			while (parent && parent->_col == RED)
			{
				Node* g = parent->_parent;
				if (g->_left == parent)
				{
					Node* u = g->_right;
					if (u && u->_col == RED)
					{
						parent->_col = u->_col = BLACK;
						g->_col = RED;
						pcur = g;
						parent = g->_parent;
					}
					else
					{
						if (pcur == parent->_left)
						{
							parent->_col = BLACK;
							g->_col = RED;
							RotateR(g);
						}
						else
						{
							pcur->_col = BLACK;
							g->_col = RED;
							RotateL(parent);
							RotateR(g);
						}
						break;
					}
				}
				else
				{
					//parent == g->_right
					Node* u = g->_left;
					if (u && u->_col == RED)
					{
						parent->_col = u->_col = BLACK;
						g->_col = RED;
						pcur = g;
						parent = g->_parent;
					}
					else
					{
						if (pcur == parent->_right)
						{
							parent->_col = BLACK;
							g->_col = RED;
							RotateL(g);
						}
						else
						{
							pcur->_col = BLACK;
							g->_col = RED;
							RotateR(parent);
							RotateL(g);
						}
						break;
					}
				}
			}
			_root->_col = BLACK;
			return true;
		}
		void InOrder()
		{
			_InOrder(_root);
			cout << endl;
		}
		bool IsRB()
		{
			if (_root == nullptr)	return true;
			if (_root->_col == RED)
				return false;
			int refNum = 0;
			Node* pcur = _root;
			while (pcur)
			{
				if (pcur->_col == BLACK)
					++refNum;
				pcur = pcur->_left;
			}
			return dfs(_root, refNum, 0);
		}
	private:
		bool dfs(Node* root, int refNum, int num)
		{
			if (root == nullptr)
			{
				return num == refNum;
			}
			if (root->_col == RED && root->_parent->_col == RED)
			{
				return false;
			}
			if (root->_col == BLACK)
				++num;
			return dfs(root->_left, refNum, num)
				&& dfs(root->_right, refNum, num);
		}
		void _InOrder(Node* root)
		{
			if (root == nullptr)
				return;
			_InOrder(root->_left);
			cout << root->_data << ' ';
			_InOrder(root->_right);
		}
		void RotateL(Node* pcur)
		{
			Node* subR = pcur->_right;
			Node* subRL = subR->_left;

			pcur->_right = subRL;
			if (subRL)	subRL->_parent = pcur;

			Node* parent = pcur->_parent;
			subR->_left = pcur;
			pcur->_parent = subR;

			subR->_parent = parent;
			if (parent)
			{
				if (parent->_left == pcur)
					parent->_left = subR;
				else
					parent->_right = subR;
			}
			else
			{
				_root = subR;
			}
		}
		void RotateR(Node* pcur)
		{
			Node* subL = pcur->_left;
			Node* subLR = subL->_right;

			pcur->_left = subLR;
			if (subLR)	subLR->_parent = pcur;

			Node* parent = pcur->_parent;
			subL->_right = pcur;
			pcur->_parent = subL;

			subL->_parent = parent;
			if (parent)
			{
				if (parent->_left == pcur)
					parent->_left = subL;
				else
					parent->_right = subL;
			}
			else
			{
				_root = subL;
			}
		}
		Node* _root = nullptr;
	};
}